/*
 * University Of Washington - Tacoma
 * TCSS-422, Operating Systems
 * Assignment 1 - Web Crawler
 * April 26, 2011
 * 
 * Team: Kernel Monkeys
 * Andrew Boguk
 * Sergiy Kulyk
 * Nicholas Swartzendruber
 */

package crawler.engine;

import java.util.Map;
import java.util.TreeMap;

import crawler.main.UI;

/**
 * The data gatherer is used to gather data
 * from multiple HTML pages. PageParsers report
 * to a data gatherer, and after each page parser has
 * finished, the data gatherer calculates statistical data
 * and constructs a reporter object for the UI. 
 * 
 * @author Nicholas Swartzendruber
 * @version 1.0
 *
 */
public class DataGatherer {

	//Fields
	
	/** 
	 * The UI that the data gatherer will be sending
	 * reporters to.
	 */
	final private UI ui;
	
	/** A map used to keep total word counts. */
	private Map<String, WordPair> totalWordMap; 
	
	/** An int used to keep track of the current page. */
	private int currentPage;
	
	/** Keeps track of the total amount of words. */
	private int totalWords;
	
	/** Keeps track of the total number of URLs found*/
	private int totalURL;
	
	/** All of the time added up for the pages. It's then averaged out. */
	private int totalTime;
	
	/** Keeps track of the time when the data gatherer was constructed. */
	private long startTime;
	
	/**
	 * Constructs the data gatherer object. Page parsers
	 * will report to the data gatherer, and when enough information
	 * is collected, the data gatherer will report to the ui.
	 * 
	 * @param ui The UI object to send reporter objects to.  
	 */
	public DataGatherer (final UI ui) {
		this.ui = ui;
		totalWordMap = new TreeMap<String, WordPair>();
		currentPage = 0;
		totalWords = 0;
		totalURL = 0;
		totalTime = 0;
		startTime = System.currentTimeMillis();
	}
	
	/**
	 * Called to add data to the overall seed data. This
	 * method should only be called by page parsers. After
	 * manipulating the passed data, a reporter object will
	 * be constructed for all the data from the last call, to
	 * just after the addition of the new data. The reporter will
	 * then be passed to the ui that this data gatherer was constructed
	 * for.
	 * 
	 * @param words A map of words to counts for up to 10 words.
	 * @param wordCount a count of total words for the page.
	 * @param linkCount a count of total links for a page.
	 * @param webpage The web address for the page parsed.
	 * @param time The total time it took to parse the data in ms.
	 */
	public synchronized void addData (final Map<String, Integer> words,
									  final int wordCount,
									  final int linkCount,
									  final String webpage,
									  final int time) {
		//We go up by one page first.
		currentPage++;
		
		//Add to our counters. 
		totalWords += wordCount;
		totalURL += linkCount;
		totalTime += time;
		
		for(String word : words.keySet()) {
			if(!totalWordMap.containsKey(word)){
				totalWordMap.put(word, new WordPair(0, 0));
			}
			WordPair wp = totalWordMap.get(word);
			
			//Add words
			wp.total += words.get(word);
			
			//Calculate new average
			wp.avg = ((double) wp.total) / currentPage;
		}
		
		
		Reporter r = new Reporter(webpage,
								  currentPage,
								  totalWords / currentPage,
								  totalURL / currentPage,
								  totalWordMap,
								  totalTime / currentPage,
								  (int)(System.currentTimeMillis() - startTime));
		
		if(ui != null && currentPage <= Engine.MAX_PAGES) {
			ui.reporterTriggered(r);
		}
	}
	
	/**
	 * @return The number of pages that have been parsed. 
	 */
	public int getCurrPage(){
		return currentPage;
	}
	
	/**
	 * A small helper class used to store
	 * statistical information about a word.
	 * Stores the avg hits per page, and total hits.
	 * @author Nicholas Swartzendruber
	 * @version 1.0
	 */
	public class WordPair{
		//Fields
		public double avg;
		public int total;
		public WordPair(final double avg, final int total) {
			this.avg = avg;
			this.total = total;
		}
	}
}
